# -*- coding: utf-8 -*-

# graphic-pppoe-client - Easy graphic networking manager
#
# Author: GoTLiuM InSPiRiT <gotlium@gmail.com>
#
# Copyright 2010, GoTLiuM InSPiRiT <gotlium@gmail.com>.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from ConfigParser import RawConfigParser
from libraries.daemon import Daemon
from libraries.fs import *
from models.main import MainModel
from helpers.main import Server, dMessage
from libraries.los import isLinux, isRoot, renameProcess, msg
from sys import modules as sysmodules
from sys import exit
import atexit
import json
import thread

PID_FILE = '/var/run/gpd.pid'
LOG_FILE = '/var/log/gpd.log'

MODULES = {}

class GPD(MainModel, Server, Daemon):
	eventsMessages = []
	eventsChkInrvl = 5
	activeConnections = {}
	config = None
	modulesIds = {}
	
	''' Initialization '''
	def __init__(self):
		# self.init(PID_FILE)
		renameProcess('gp-daemon')
		atexit.register(self._onExit)
		self._initModules()
		self._initConfig()
		# thread.start_new_thread(self._initEvents, ())
		self._initServer((self._host, self._port))

	def _initConfig(self):
		self.config = config = RawConfigParser()
		config.read(BASE_DIR + '/config.cfg')
		self._host = config.get('Server', 'host')
		self._port = int(config.get('Server', 'port'))

	def _initModules(self):
		self.loadTables('Main')
		modules = self.getAllModules()
		if modules['num'] > 0:
			for module_row in modules['result']:
				if module_row['is_enabled'] == 'true':
					self.loadModule(module_row['alias'])
				self.modulesIds[module_row['alias']] = module_row['id']
		MODULES['Main'] = self

	''' Method for loading module '''
	def loadModule(self, module):
		if module in MODULES: return
		importedModule = __import__(
			'modules.%s' % module.lower(), fromlist="modules"
		)
		mclass = getattr(importedModule, module)
		MODULES[module] = mclass(self)
		for parent in MODULES[module].__class__.__bases__:
			self.loadTables(parent.__name__)
		msg("Module '%s' is loaded." % module)

	''' Method for unloading module '''
	def uloadModule(self, module):
		if module in MODULES.keys():
			del(MODULES[module])
		for mod in sysmodules:
			if mod.find(module.lower()) != -1:
				del(sysmodules[mod])
				break
		msg("Module '%s' is unloaded." % module)

	'''
	Method for messaging exchange with module.
	'''
	def _callModule(self, receivedMessage = None):
		if receivedMessage:
			try:
				message = json.loads(receivedMessage)
			except:
				return dMessage(-1, "Can't decode client message.")
			try:
				module = message['Module']
				action = message['Action']
			except:
				return dMessage(-1, 'Format error.')

			if action.find('_') != -1:
				return dMessage(-1, "Module doesn't have this action.")
			elif module in MODULES:
				if hasattr(MODULES[module], action):
					try:
						method = getattr(MODULES[module], action)
					except Exception, emsg:
						return dMessage(-1, "%s" % emsg)

					# Calling method from module
					try:
						del message['Module'], message['Action']
						if module != 'Main':
							if 'connId' not in message.keys():
								message['id'] = self.modulesIds[module]
							else:
								message['id'] = message['connId']
								del message['connId']
						response = method(**message)
					except Exception, emsg:
						return dMessage(-1, "%s" % emsg)

					# Making response message
					if isinstance(response, dict) or isinstance(response, list):
						try:
							return dMessage(0, "%s" % json.dumps(response))
						except:
							return dMessage(-1, "Can't dump module response.")
					elif isinstance(response, str) or isinstance(response, int):
						return dMessage(0, "%s" % response)
					else:
						return dMessage(0, "Successful")
				else:
					return dMessage(-1, "Module doesn't have this action.")
			else:
				return dMessage(-1, "Module not loaded.")
		else:
			return dMessage(-1, "Message can't be null.")

	''' Method for get events messages in read mode '''
	def _getModulesEvents(self):
		return self.eventsMessages

	''' Calling standard methods from all modules every N time '''
	def _initEvents(self):
		# TODO: fix it when first module is done
		import time
		while True:
			current = time.time()
			self.eventsMessages.append(current)
			time.sleep(2)
		if len(self.eventsMessages) > 500:
			del self.eventsMessages[:500]

	def _onExit(self):
		MainModel._onExit(self)
		Daemon._onExit(self)
		msg("Exit.")


if __name__ == '__main__':
	if not isRoot():
		msg('Are you "Root"?')
		exit(1)
	elif not isLinux():
		msg('This platform not supported!')
		exit(1)

	# TODO: Logger lib
	# TODO: Tracebacks / Saving to log file
	try:
		gp = GPD()
	except KeyboardInterrupt:
		pass
	except Exception, errmsg:
		print errmsg

	exit(0)
